import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Object which stored words and incremental counters for them
 * To be used for describing documents and corpus
 * @author tomalteman
 *
 */
public class wordcount {
	
	//Allows corpus to monitor presence of word for each topic
	private HashMap<String,int[]> tcount;
	
	
	public ArrayList<String> keys;
	private HashMap<String,Integer> list;
	private int total;
	
	//Only used when represnting corpus
	private int documents;
	
	private String topic;
	
	
	public wordcount()
	{
		keys = new ArrayList<String>();
		list = new HashMap<String,Integer>();
		tcount = new HashMap<String,int[]>();
		total=0;
		documents=0;
		topic="";
	}
	
	public wordcount(String t)
	{
		keys = new ArrayList<String>();
		list = new HashMap<String,Integer>();
		tcount = new HashMap<String,int[]>();
		total=0;
		documents=0;
		topic=t;
	}
	
	/*
	 * ONLY FOR INDIVIDUAL WORDS
	 */
	public wordcount(ArrayList<String> words)
	{
		keys = new ArrayList<String>();
		list = new HashMap<String,Integer>();
		tcount = new HashMap<String,int[]>();
		total=0;
		documents=0;
		topic="";
		
		for(int i=0;i<words.size();i++) add(words.get(i));
	}
	
	public void setTopic(String t)
	{
		topic=t;
	}
	
	public String getTopic()
	{
		return topic;
	}
	
	/**
	 * Adds a word to the wordcounter and key list
	 * @param word
	 */
	public void add(String word)
	{
		int value;
		
		//If already in list then simply increment counter
		if(list.containsKey(word))
		{
			value = list.get(word) + 1;
			list.put(word, value);
			total++;
		}
		else
		{
			list.put(word, 1);
			total++;
		}
		
		if(!keys.contains(word)) keys.add(word);
	}
	
	/**
	 * Adds a word to the corpus count and to the topic array
	 * @param word
	 * @param topic
	 */
	public void addToCorpus(String word, int topic,int size)
	{
		add(word);
		int[] t = new int[size];
		
		for(int i=0;i<t.length;i++) t[i]=0;
		
		if(tcount.containsKey(word))
		{
			t = tcount.get(word);
			
		}
		
		t[topic]++;
		tcount.put(word, t);
	}
	
	/**
	 * Returns tcount array for a word
	 * @param word
	 * @return
	 */
	public int[] getTcount(String word)
	{
		return tcount.get(word);
	}
	
	/**
	 * Set wordcounter when adding word from file or adding from elsewhere
	 * @param word
	 * @param value
	 */
	public void add(String word, int value)
	{
		if(list.containsKey(word)) list.put(word, list.get(word) + value);
		else list.put(word, value);
		
		if(value>0) total = total + value;
		
		if(!keys.contains(word)) keys.add(word);
	}
	
	public int getSize()
	{
		return keys.size();
	}
	
	/**
	 * Removes a word from the wordcount
	 * @param word
	 */
	public void remove(String word)
	{
		if(!list.containsKey(word)) 
			{
				System.err.println(word + " not present");
				return;
			}
		
		int val = list.get(word);
		list.remove(word);
		
		total = total - val;
		
		//keys.remove(keys.indexOf(word));
	}
	
	/**
	 * Gets total number of words
	 * @return
	 */
	public int getTotal()
	{
		return total;
	}
	
	/**
	 * Increments doc counter
	 */
	public void addDoc()
	{
		documents++;
	}
	
	/**
	 * Return total number of documents 
	 */
	public int getDoc()
	{
		return documents;
	}
	
	/**
	 * Returns count for a given word
	 * 
	 * @param s
	 * @return
	 */
	public int getCount(String s)
	{
		if(!list.containsKey(s)) return -1;
		
		return list.get(s);
	}

	/**
	 * Returns list of words in form of ArrayList to be written to file
	 */
	public ArrayList<String> getList(boolean corpus)
	{
		ArrayList<String> lines = new ArrayList<String>();
		
		//First line of corpus is number of documents
		if(corpus) lines.add(Integer.toString(getDoc()));
		
		Iterator iter = list.entrySet().iterator();
	    while (iter.hasNext()) {
	        Map.Entry<String,Integer> val = (Map.Entry<String,Integer>)iter.next();
	        lines.add(new String(val.getKey()+" "+val.getValue()));
	        //System.out.println(new String(val.getKey()+" "+val.getValue()));
	    }
		
		return lines;
	}
	
	//public ArrayList<String>
	
	/**
	 * Add a word to vocab
	 * When wordcount is used to convert words to indexes
	 */
	public void addWord(String word)
	{
		total++;
		
		if(!list.containsKey(word)) list.put(word, total);
		else total--;
	}
	
	/**
	 * Gets a word index from vocab
	 * Returns -1 if not found
	 * @param word
	 * @return
	 */
	public int getWord(String word)
	{
		if(list.get(word) == null) return -1;
		return list.get(word);
	}
	
	/**
	 * Returns a list of entries for this wordcount
	 */
	public ArrayList<entry> getEntries()
	{
		ArrayList<entry> e = new ArrayList<entry>();
		
		Iterator iter = list.entrySet().iterator();
	    while (iter.hasNext()) {
	        Map.Entry<String,Integer> val = (Map.Entry<String,Integer>)iter.next();
	        e.add(new entry(val.getKey(),val.getValue()));
	        //System.out.println(new String(val.getKey()+" "+val.getValue()));
	    }
	    
	    return e;
	}
	
	/**
	 * Returns a count in the form of an entry
	 * @param s
	 * @return
	 */
	public entry getEntry(String s)
	{
		entry e = new entry();
		
		e.word = s;
		e.count = list.get(s);
		
		return e;
	}
	
	/*
	 * Indicates whether string is in wordcount
	 */
	public boolean contains(String s)
	{
		return list.containsKey(s.toLowerCase());
	}
	
	public void loadFromFile(ArrayList<String> words, boolean corpus)
	{
		int start = 0;
		//First line is documents
		if(corpus) 
			{
				documents = Integer.parseInt(words.get(0));
				start = 1;
			}
		
		String[] split;
		
		for(int i=start;i<words.size();i++)
		{
			split = words.get(i).split(" ");
			list.put(split[0], Integer.parseInt(split[1]));
			keys.add(split[0]);
			total++;
		}
	}
	
	public void print()
	{
		ArrayList<String> p = getList(false);
		
		for(int i=0;i<p.size();i++) System.out.println(p.get(i));
	}
	
	/**
	 * Prints corpus complete with wordcount per topic
	 */
	public void printCorpus()
	{
		ArrayList<String> p = getList(false);
		
		for(int i=0;i<p.size();i++) 
			{
				String[] split = p.get(i).split(" ");
				int[] t = tcount.get(split[0]);
				System.out.println(p.get(i) + " {" + t[0] + ","+ t[1] + ","+ t[2] + ","+ t[3] + "}");
			}
	}
	
	/**
	 * Prints out line with word and topic count
	 * @param word
	 */
	public String printLine(String word, double ig)
	{
		String text="";
		int[] t = tcount.get(word);
		
		text = word + " {";
		
		for(int i : t) text = text + ","+ i;
		
		text = text + "} " +ig;
		return text;
	}
}
